-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[Clang] SubstituteConstraintExpressionWithoutSatisfaction needs an unevaluated context #123883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…evaluated context It turns out that the substitution for expression comparing also needs an unevaluated context, otherwise any reference to immediate functions might not be properly handled.
…nder unevaluated context
|
@llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) ChangesIt turns out that the substitution for expression comparing also needs As a fallout, this also guards the VLA transformation under unevaluated context Fixes #123472 Full diff: https://github.com/llvm/llvm-project/pull/123883.diff 5 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f75c726e2751cf..5a5a97b341881a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -966,7 +966,7 @@ Bug Fixes to C++ Support
constraints are applied. (#GH122134)
- Fixed canonicalization of pack indexing types - Clang did not always recognized identical pack indexing. (#GH123033)
- Fixed a nested lambda substitution issue for constraint evaluation. (#GH123441)
-
+- Fixed various false diagnostics related to the use of immediate functions. (#GH123472)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 8dd72db8f5b4a2..bf017a3131b4a7 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -248,6 +248,25 @@ ExprResult Parser::ParseArrayBoundExpression() {
// If we parse the bound of a VLA... we parse a non-constant
// constant-expression!
Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true;
+ // For a VLA type inside an unevaluated operator like:
+ //
+ // sizeof(typeof(*(int (*)[N])array))
+ //
+ // in which the expression N is supposed to be ODR-used, as is the `array`.
+ // Initially when encountering `array`, it is deemed unevaluated and non-ODR
+ // used because that occurs before parsing the type cast. Therefore we use
+ // Sema::TransformToPotentiallyEvaluated() to rebuild the expression to ensure
+ // it's actually ODR-used.
+ //
+ // However, in other unevaluated contexts as in constraint substitution, it
+ // would end up rebuilding the type twice which is unnecessary. So we push up
+ // a flag to help distinguish these cases.
+ for (auto Iter = Actions.ExprEvalContexts.rbegin() + 1;
+ Iter != Actions.ExprEvalContexts.rend(); ++Iter) {
+ if (!Iter->isUnevaluated())
+ break;
+ Iter->InConditionallyConstantEvaluateContext = true;
+ }
return ParseConstantExpressionInExprEvalContext(NotTypeCast);
}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 6a40a59c977d78..8a77cbf8c9477b 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1027,6 +1027,9 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
/*NewThisContext=*/false);
}
+ EnterExpressionEvaluationContext UnevaluatedContext(
+ S, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction(
const_cast<clang::Expr *>(ConstrExpr), MLTAL);
if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ae40895980d90a..444640b27de1fe 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4630,8 +4630,9 @@ ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
// Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to
// properly deal with VLAs in nested calls of sizeof and typeof.
- if (isUnevaluatedContext() && ExprKind == UETT_SizeOf &&
- TInfo->getType()->isVariablyModifiedType())
+ if (currentEvaluationContext().isUnevaluated() &&
+ currentEvaluationContext().InConditionallyConstantEvaluateContext &&
+ ExprKind == UETT_SizeOf && TInfo->getType()->isVariablyModifiedType())
TInfo = TransformToPotentiallyEvaluated(TInfo);
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 7cb5cfc10b9a7b..6c1a229a9fddab 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -737,3 +737,17 @@ ptr<U> make_item(auto &&args)
ptr<char> p;
} // namespace GH114685
+
+namespace GH123472 {
+
+consteval bool fn() { return true; }
+
+struct S {
+ template <typename T>
+ static consteval void mfn() requires (bool(&fn));
+};
+
+template <typename T>
+consteval void S::mfn() requires (bool(&fn)) {}
+
+}
|
Co-authored-by: cor3ntin <[email protected]>
cor3ntin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
It turns out that the substitution for expression comparing also needs
an unevaluated context, otherwise any reference to immediate functions
might not be properly handled.
As a fallout, this also guards the VLA transformation under unevaluated context
with
InConditionallyConstantEvaluateContextto avoid duplicate diagnostics.Fixes #123472